/**
  *	Networking semester project
  */

#include <avr/io.h>			// Contains port name definitions, etc.
#include <avr/interrupt.h>	// Contains declaration for sei()
#include "globaldef.h"		// Contains definition for F_CPU (needed by delay.h)
#include <util/delay.h>		// Contains _delay_ms and _delay_us functions
#include <inttypes.h>		// Contains C99 data types
#include "lcd.h"			// Contains many lcd functions
#include <stdlib.h>
#include <stdbool.h>

//State Flags
bool BUSY = false;
bool IDLE = false;
bool COLLISION = false;
bool SENDING = false;
bool DETECTEDCOLLISION = false;
void initialize();
char USARTReadChar();
void USARTInit(uint16_t ubrr_value);
void USARTWriteChar(char);
void write1();
void write0();
void send_message(char input[]);

int main()
{
	
	initialize();
		
	//Infinate loop to see what the status is
	while (1)

	{

		//start new message
		lcd_clear();
		lcd_home();
		
		int i = 0;
		char input[255];
		
		//while the message is less then 128 and message not sent
		//wait for input
		while(i < 255){

		 	char temp = USARTReadChar();

			
   			lcd_print_char(temp);

			//if enter pressed then
			//break out of loop and send message
			if(temp == 13){
				input[i] = temp;
				break;
			//else add character to message
			}else{
				input[i] = temp;
				//echo it to hyper terminal
				USARTWriteChar(temp);
			}
		
			//increment counter;
			i++;
		}
		
		SENDING = true;
		if(!IDLE){
			//lcd_clear();
			//lcd_home();
			//lcd_print_string("Bus is busy, please wait.");
		}
		while(!IDLE){
			//lcd_clear();
		}
		//lcd_clear();
		//lcd_home();
		//lcd_print_string("Sending Message...");
		send_message(input);
		SENDING = false;
		//lcd_clear();
		//lcd_home();
		//lcd_print_string("Transmission complete!");
		//_delay_ms(2000);
		

	}	

	
}

void initialize(){
	//Setup pin 7 for output and pin 6 as input
	DDRD = 0x00;
	PORTD= 0xFF;
	PIND = 0xFF;

	//Setup LEDs
	DDRB =0xFF;
	PORTB = 0x00;

	lcd_init('C');
	lcd_clear();
	lcd_home();

	//Enable interupts
	sei();
	//Enable external interupt 1
	GICR = (1<<INT1);
	//Setup INT1 to trigger on a logical change
	MCUCR = (0<<ISC11)|(1<<ISC10);
	//Enable the overflow interupt
	TIMSK = (1<<TOIE0);
	// setup the clock to trigger every 3.2 ms
	TCNT0 = 175;
	//set the clock to 1024
	TCCR0 = (1<<CS02)|(1<<CS00);

	USARTInit(103);
	

}

ISR(INT1_vect){
	PORTB = 0b00000010;
	BUSY = true;
	IDLE = false;


	TCNT0 = 175;
}

ISR(TIMER0_OVF_vect){
	if(((PIND)&(1<<PD6))==0){
		
			PORTB = 0b00000100;
			COLLISION =true;
			IDLE = false;
			PORTD = (1<<PD7);

			if(SENDING){
				DETECTEDCOLLISION = true;
			}
		
		
	}
	else{
		
			PORTB = 0b00000001;
			IDLE = true;
			BUSY = false;
			COLLISION = false;
			PORTD = (1<<PD7);
		
		
	}

	TCNT0 =175;
}

//from USART. This function will wait untill data is
//available.
char USARTReadChar()
{
   //Wait untill a data is available

   while((UCSRA & (1<<RXC)) == 0);

   //Now USART has got data from host
   //and is available is buffer

   return UDR;
}

void USARTInit(uint16_t ubrr_value)
{

	//9600 data rate
	//2 stop bits
	//no parity
	//no flow control
   //Set Baud rate

   UBRRL = (unsigned char) ubrr_value;
   UBRRH = (unsigned char) (ubrr_value>>8);
	
   //Enable The receiver and transmitter

   UCSRB = (1<<RXEN)|(1<<TXEN);

   UCSRC = (1<<URSEL) /* write to UCSRC */ |(1<<USBS) /* use 2 stop bits */ |(3<<UCSZ0) /* use 8-bit data frame */;


}




//This fuction writes the given "data" to
//the USART which then transmit it via TX line
void USARTWriteChar(char data)
{
   //Wait untill the transmitter is ready

   while(!(UCSRA & (1<<UDRE)))
   {
      //Do nothing
   }

   //Now write the data to USART buffer

   UDR=data;
}

void write1(){

	PORTD = (0<<PD7);
	_delay_ms(2.5);
	PORTD = (1<<PD7);
}
void write0(){

	PORTD = (1<<PD7);
	_delay_ms(2.5);
	PORTD = (0<<PD7);
}

void send_message(char input[]){

	//for each character
	for(int i = 0; i < 255; i++){
		
		if(input[i] == 13){
			break;
		}
		uint8_t character = input[i];

		for(int i = 7; i >=0; i--){

		if(DETECTEDCOLLISION){
			PORTD = (1<<PD7);
			while(!IDLE){}
			uint8_t random = rand();
			if(random < 2.5){
				//lcd_clear();
				//lcd_home();
				//lcd_print_string("Waiting for ");
				//lcd_print_uint8(2.5);
				//lcd_print_string("ms");
				_delay_ms(2.5);
			}
			else{
				//lcd_clear();
				//lcd_home();
				//lcd_print_string("Waiting for ");
				//lcd_print_uint8(random);
				//lcd_print_string("ms");
				_delay_ms(random);
			}
			DETECTEDCOLLISION = false;
			if(BUSY){
				//lcd_clear();
				//lcd_print_string("Bus is busy, please wait.");
			}
			
			send_message(input);
			break;
		}


			if(((character)&(1<<i))==0){
				write0();
			}
			else{
				write1();
			}
			_delay_ms(2.5);	
		}

	}
	DETECTEDCOLLISION = false;

}


